﻿using Bandit.Helpers;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ETC.DLEDPositionTool.Helpers
{
    public class TestErrorEventArgs
    {
        public Exception Exception { get; private set; }

        public string Title { get; private set; }

        public TestErrorEventArgs(Exception ex, string title)
        {
            this.Exception = ex;
            this.Title = title;
        }
    }
    public abstract class DeviceBase
    {
        #region 委托事件
        public delegate void ConnectedHandler(DeviceBase sender, bool isConnect);
        /// <summary>
        /// 连接状态变更事件
        /// </summary>
        public event ConnectedHandler OnConnectedChanged;

        public delegate void OnErrorHandler(DeviceBase sender, TestErrorEventArgs e);
        /// <summary>
        /// 错误触发事件
        /// </summary>
        public event OnErrorHandler OnError;
        #endregion

        #region 字段

        protected AutoResetEvent _AutoResetEvent;

        //protected bool _ResponseState = false;

        protected string _ResponseData = string.Empty;

        #endregion

        #region 属性
        public bool IsAutoReopen { get; set; }

        public string Tag { get; set; }

        /// <summary>
        /// PortName
        /// </summary>
        public string PortName { get; private set; }

        /// <summary>
        /// 是否连接
        /// </summary>
        public bool IsConnected
        {
            get
            {
                return this.BanditSerialPort != null && this.BanditSerialPort.IsOpen;
            }
        }

        /// <summary>
        /// 是否接收结束
        /// </summary>
        public bool IsFinished
        {
            get;
            set;
        }

        /// <summary>
        /// BanditSerialPort
        /// </summary>
        public Bandit.Helpers.BanditSerialPort BanditSerialPort
        {
            get;
            set;
        }
        #endregion

        #region 构造函数

        public DeviceBase(string portName)
        {
            this.PortName = portName;
            this._AutoResetEvent = new AutoResetEvent(false);
            this.IsAutoReopen = true;
        }

        #endregion

        public void Connect(string newLine, int baudRate, int dataBits, Parity parity, StopBits stopBits)
        {
            this.BanditSerialPort = new BanditSerialPort(this.PortName);
            this.BanditSerialPort.NewLine = newLine;
            this.BanditSerialPort.BaudRate = baudRate;
            this.BanditSerialPort.DataBits = dataBits;
            this.BanditSerialPort.Parity = parity;
            this.BanditSerialPort.StopBits = stopBits;
            this.BanditSerialPort.EndFlag = "}";
            //this.BanditSerialPort.RtsEnable = true;

            //this.BanditSerialPort.DtrEnable = true;

            this.BanditSerialPort.OnStatusChanged += (sender, isOpen) =>
            {
                this.FireOnConnectedChanged();

                //if (!isOpen.IsOpen && this.IsAutoReopen)
                //{
                //    this.BanditSerialPort.Open();
                //}
            };

            this.BanditSerialPort.OnReceived += BanditSerialPort_OnReceived;

            this.BanditSerialPort.OnError += (sender, e) =>
            {
                this.FireOnError(e.Exception, "BanditSerialPort.OnError");
            };

            if (!this.BanditSerialPort.Open())
            {
                Task.Factory.StartNew((Action)delegate
                {
                    while (this.BanditSerialPort != null && !this.BanditSerialPort.Open())
                    {
                        Thread.Sleep(1000);
                        this.FireOnConnectedChanged();
                    }
                }).LogExceptions("BanditSerialPort.Connect");
            }
        }

        public virtual void Send(string cmd, bool isThread = true, int delayMS = 200)
        {
            //this._ResponseState = false;

            this._ResponseData = string.Empty;

            LogHelper.Info(cmd);

            if (isThread)
            {
                Task.Factory.StartNew(() =>
                {
                    Thread.Sleep(delayMS);

                    this.BanditSerialPort.Send(cmd, DataTypeBySerialPort.Text, true);

                }).LogExceptions("Send - " + cmd);
            }
            else
            {
                this.BanditSerialPort.Send(cmd, DataTypeBySerialPort.Text, true);
            }
        }

        protected virtual void BanditSerialPort_OnReceived(object sender, OnReceivedArgs e)
        {

            Console.WriteLine(e.NormalData);
        }

        /// <summary>
        /// 线程继续
        /// </summary>
        /// <returns></returns>
        public bool Set()
        {
            return this._AutoResetEvent.Set();
        }

        /// <summary>
        /// 线程等待
        /// </summary>
        /// <param name="second"></param>
        /// <returns></returns>
        public bool Wait(double second)
        {
            this._AutoResetEvent.Reset();

            return this._AutoResetEvent.WaitOne(TimeSpan.FromSeconds(second));
        }

        /// <summary>
        /// 触发USB连接状态变更事件
        /// </summary>
        public void FireOnConnectedChanged()
        {
            if (OnConnectedChanged != null)
            {
                OnConnectedChanged(this, this.IsConnected);
            }
        }

        /// <summary>
        /// 触发错误事件
        /// </summary>
        protected virtual void FireOnError(Exception ex, string title)
        {
            if (OnError != null)
            {
                OnError(this, new TestErrorEventArgs(ex, title));
            }
        }
    }
}
